package cn.itcast.multi.thread.threadpool;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

/**
 * CompletionService能够实现，哪个任务先运行完毕就返回，而不是按顺序返回，这样能够极大的提升效率
 * create by zhangtian3 on 2019/3/20
 */
public class CompletionServiceDemo {
    public static void main(String[] args) throws Exception {
        /**
         * 内部维护11个线程的线程池
         */
        ExecutorService exec = Executors.newFixedThreadPool(11) ;

        /**
         * 容量为10的堵塞队列
         */
        final BlockingQueue<Future<Integer>> queue = new LinkedBlockingQueue<Future<Integer>>() ;
        final CompletionService<Integer> completionService = new ExecutorCompletionService<Integer>(exec, queue) ;

        /**
         * 模拟瞬间产生10个任务，且每一个任务运行时间不一致
         */
        for(int i = 0; i < 10; i++) {
            completionService.submit(new Callable<Integer>() {
                @Override
                public Integer call() throws Exception {
                    int random = 5000 ;//ThreadLocalRandom.current().nextInt(1000) ;
                    Thread.sleep(random);
                    System.out.println(Thread.currentThread().getName() + " 歇息了 " + random);
                    return random;
                }
            }) ;
        }

        long s = System.currentTimeMillis() ;

        /**
         * 马上输出结果
         */
        for (int i = 0; i < 10; i++) {
            try {
                // 谁最先运行完毕，直接返回
                Future<Integer> f = completionService.take();
                System.out.println(f.get());
            }catch (Exception e) {
                e.printStackTrace();
            }
        }

        System.out.println("运行任务消耗了 ：" + (System.currentTimeMillis() - s) +"毫秒");


        // invokeAll返回是等待全部线程运行完毕的。这点来说，我认为可用性不如CompletionService。
        System.out.println("======================== 华丽的分隔符 =========================");
        // ****************************** 比较一下原始的 **********************
        List<Callable<Integer>> tasks = new ArrayList<Callable<Integer>>(10);
        Callable<Integer> task = null;
        for(int i = 0; i < 10; i++) {
            task = new Callable<Integer>() {
                @Override
                public Integer call() throws Exception {
                    int random = 5000 ;// ThreadLocalRandom.current().nextInt(1000) ;
                    Thread.sleep(random);
                    System.out.println(Thread.currentThread().getName() + " 歇息了 " + random);
                    return random;
                }
            } ;

            tasks.add(task) ;
        }

        long t = System.currentTimeMillis() ;
        List<Future<Integer>> results = exec.invokeAll(tasks) ;
        /**
         * 马上输出结果
         */
        for (int i = 0; i < 10; i++) {
            try {
                // 谁最先运行完毕，直接返回
                Future<Integer> f = results.get(i);
                System.out.println(f.get());
            }catch (Exception e) {
                e.printStackTrace();
            }
        }

        System.out.println("运行任务消耗了 ：" + (System.currentTimeMillis() - t) +"毫秒");

        exec.shutdown();
    }
}
